<template>
  <div id="encrypt">
    <el-container>
      <el-header>文件加密工具</el-header>
      <el-main>
        <el-upload
            class="upload-demo"
            drag
            action="#"
            :on-change="handleFileChange"
            :auto-upload="false"
        >
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        </el-upload>

        <el-select v-model="algorithm" placeholder="请选择加密算法">
          <el-option label="AES" value="AES"></el-option>
          <el-option label="DES" value="DES"></el-option>
          <el-option label="3DES" value="3DES"></el-option>
          <el-option label="SM4" value="SM4"></el-option>
        </el-select>

        <el-input
            v-if="showKeyInput"
            v-model="key"
            placeholder="请输入密钥"
        ></el-input>
        <el-button @click="generateKey" type="success">生成密钥</el-button>

        <el-button @click="encryptFile" type="danger">加密文件</el-button>

        <p v-if="encryptedData">加密后的数据已自动下载</p>

      </el-main>
    </el-container>
  </div>
</template>

<script>
import CryptoJS from 'crypto-js';
import SM4 from 'sm-crypto';

export default {
  name: 'Encrypt',
  data() {
    return {
      file: null,
      algorithm: 'AES',
      key: '',
      iv: '', // 初始化向量
      showKeyInput: true,
      encryptedData: ''
    };
  },
  methods: {
    handleFileChange(file) {
      this.file = file.raw;
    },
    generateKey() {
      let keyLength, ivLength;
      switch (this.algorithm) {
        case 'AES':
          keyLength = 16; // AES-128
          ivLength = 16; // AES block size
          break;
        case 'DES':
          keyLength = 8; // DES
          ivLength = 8; // DES block size
          break;
        case '3DES':
          keyLength = 24; // 3DES
          ivLength = 8; // DES block size
          break;
        case 'SM4':
          keyLength = 16; // SM4
          ivLength = 16; // SM4 block size
          break;
        default:
          keyLength = 16;
          ivLength = 16;
      }
      this.key = CryptoJS.lib.WordArray.random(keyLength).toString(CryptoJS.enc.Hex);
      this.iv = CryptoJS.lib.WordArray.random(ivLength).toString(CryptoJS.enc.Hex);
    },
    encryptFile() {
      if (!this.file || !this.key) {
        alert('请选择文件并填写或生成密钥和初始化向量');
        return;
      }

      const reader = new FileReader();
      reader.onload = (event) => {
        const fileContent = event.target.result;
        let encrypted;

        switch (this.algorithm) {
          case 'AES':
            encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Latin1.parse(fileContent), this.key, { iv: CryptoJS.enc.Hex.parse(this.iv) }).toString();
            break;
          case 'DES':
            encrypted = CryptoJS.DES.encrypt(CryptoJS.enc.Latin1.parse(fileContent), this.key, { iv: CryptoJS.enc.Hex.parse(this.iv) }).toString();
            break;
          case '3DES':
            encrypted = CryptoJS.TripleDES.encrypt(CryptoJS.enc.Latin1.parse(fileContent), this.key, { iv: CryptoJS.enc.Hex.parse(this.iv) }).toString();
            break;
          case 'SM4':
            // const sm4Key = this.key.slice(0, 32); // Ensure key length is 16 bytes for SM4
			const sm4Key = this.normalizeKeyOrIv(this.key, 32);
            const sm4Iv = this.iv.slice(0, 32); // Ensure IV length is 16 bytes for SM4
            encrypted = SM4.sm4.encrypt(fileContent, sm4Key, { mode: 'cbc', iv: sm4Iv });
            break;
          default:
            encrypted = '';
        }

        this.encryptedData = encrypted;
        this.downloadEncryptedFile(encrypted);
      };

      reader.readAsBinaryString(this.file);
    },
	normalizeKeyOrIv(value, length) {
	      if (value.length < length) {
	        // 填充到指定长度
	        return value.padEnd(length, '0');
	      } else if (value.length > length) {
	        // 截取到指定长度
	        return value.slice(0, length);
	      }
	      return value;
	    },
    downloadEncryptedFile(data) {
      const originalFileName = this.file.name;
      const fileNameParts = originalFileName.split('.');
      const baseName = fileNameParts.slice(0, -1).join('.');
      const extension = fileNameParts[fileNameParts.length - 1];
      let version = 1;
      let newFileName = `${baseName} (${version}).${extension}.enc`;

      while (localStorage.getItem(newFileName)) {
        version++;
        newFileName = `${baseName} (${version}).${extension}.enc`;
      }

      localStorage.setItem(newFileName, 'exists');

      // 将 key 和 iv 存储在加密文件中
      const metadata = JSON.stringify({ key: this.key, iv: this.iv });
      const blob = new Blob([metadata, '\n', data], { type: 'text/plain' });
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = newFileName;
      document.body.appendChild(a);
      a.click();
      a.remove();
      window.URL.revokeObjectURL(url);
    }
  }
};
</script>

<style scoped>
#encrypt {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.upload-demo {
  margin-bottom: 20px;
}
</style>



